"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const git_utils_1 = require("../utils/git-utils");
const fs = require('fs-extra');
const bootstrap = () => __awaiter(void 0, void 0, void 0, function* () {
    const path = require('path');
    process.env.BABEL_ENV = 'production';
    process.env.NODE_ENV = 'production';
    const paths = require('../config/paths');
    const compileEnvFile = path.resolve(paths.appConfig, 'compileBuildEnv.js');
    if (fs.existsSync(compileEnvFile)) {
        Object.assign(process.env, require(compileEnvFile));
    }
    const chalk = require('react-dev-utils/chalk');
    const webpack = require('webpack');
    const bfj = require('bfj');
    const configFactory = require('../config/webpack.ms.config');
    const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
    const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
    const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
    const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild;
    const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
    const useYarn = fs.existsSync(paths.yarnLockFile);
    // These sizes are pretty large. We'll warn for bundles exceeding them.
    const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
    const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
    const microInfoFile = path.resolve(paths.appPath, 'package.json');
    const appPackage = require(microInfoFile); // 读取 package.json 的 内容
    if (!appPackage.name) {
        throw '不存在子模块名称';
    }
    console.log(`正在编译 ${appPackage.name} 模块`);
    // Create the production build and print the deployment instructions.
    function build(previousFileSizes) {
        return __awaiter(this, void 0, void 0, function* () {
            console.log('Creating an optimized production build...');
            // Generate configuration
            const config = configFactory('production'); // 获取配置文件
            let compiler = webpack(config); // 编译配置
            return new Promise((resolve, reject) => {
                compiler.run((err, stats) => {
                    let messages;
                    if (err) {
                        if (!err.message) {
                            return reject(err);
                        }
                        messages = formatWebpackMessages({
                            errors: [err.message],
                            warnings: [],
                        });
                    }
                    else {
                        messages = formatWebpackMessages(stats.toJson({
                            all: false,
                            warnings: true,
                            errors: true,
                        }));
                    }
                    if (messages.errors.length) {
                        // Only keep the first error. Others are often indicative
                        // of the same problem, but confuse the reader with noise.
                        if (messages.errors.length > 1) {
                            messages.errors.length = 1;
                        }
                        return reject(new Error(messages.errors.join('\n\n')));
                    }
                    if (process.env.CI &&
                        (typeof process.env.CI !== 'string' ||
                            process.env.CI.toLowerCase() !== 'false') &&
                        messages.warnings.length) {
                        console.log(chalk.yellow('\nTreating warnings as errors because process.env.CI = true.\n' +
                            'Most CI servers set it automatically.\n'));
                        return reject(new Error(messages.warnings.join('\n\n')));
                    }
                    const resolveArgs = {
                        stats,
                        previousFileSizes,
                        warnings: messages.warnings,
                        config,
                    };
                    const assetsChunkData = stats.toJson().assetsByChunkName; // 得到 编译后的 主文件
                    // 生成编译后文件
                    return bfj
                        .write(paths.appRootBuild +
                        `/packages/${appPackage.name}/bundle-stats.json`, assetsChunkData)
                        .then(() => {
                        return updateParentMicroConfig(assetsChunkData); // 更新 microConfig 文件
                    }) // 先 写入主文件 地址  然后更新 父模块microConfig.json
                        .then(() => resolve(resolveArgs))
                        .catch(error => reject(new Error(error)));
                });
            });
        });
    }
    /**
     * 更新汇总文件
     * @param assetsChunkData
     */
    function updateParentMicroConfig(assetsChunkData) {
        return __awaiter(this, void 0, void 0, function* () {
            const cpaasRootConfig = paths.getCpaasConfig(paths.appPath) || {}; // .cpaasrc.js 里的文件
            let indexAssets = typeof assetsChunkData.main === 'string'
                ? [assetsChunkData.main]
                : assetsChunkData.main;
            if (assetsChunkData['runtime~main']) {
                if (typeof assetsChunkData['runtime~main'] === 'string') {
                    indexAssets.unshift(assetsChunkData['runtime~main']);
                }
                else {
                    indexAssets = assetsChunkData['runtime~main'].concat(indexAssets);
                }
            }
            let IS_PUBLIC_MS = process.env.Build_MICRO_WITHOUT_PARENT === 'true'; // 是否外部 资源  默认为 true
            const microPackageConfig = Object.assign({ name: appPackage.name, indexAssets }, cpaasRootConfig.package);
            // if (!IS_PUBLIC_MS && microPackageConfig.public) {
            //   IS_PUBLIC_MS = true;
            // }
            // if (IS_PUBLIC_MS && !microPackageConfig.public) {
            //   microPackageConfig.public = true;
            // }
            const microConfigData = {
                [appPackage.name]: microPackageConfig,
            };
            const microModueInfoFile = path.resolve(paths.appRootBuild, `packages/${appPackage.name}/package.json`); // 本来是没有 package.json 的
            // let oldMicroMapConfig;
            let commitHash;
            try {
                commitHash = yield git_utils_1.getHeadId();
            }
            catch (_a) { }
            yield bfj.write(microModueInfoFile, Object.assign({ commitHash, version: appPackage.version }, microPackageConfig)); // 写入 新的 package.json 内容
            let microMapConfigPath = path.resolve(paths.appRootBuild, 'packages/microConfig.json'); // microConfig
            // 肯定 不存在 microConfig.json
            // if (fs.existsSync(microMapConfigPath)) {
            //   oldMicroMapConfig = fs.readJSONSync(microMapConfigPath);
            // } else {
            // }
            let resultMicroConfigData = Object.assign({}, microConfigData);
            fs.writeFileSync(microMapConfigPath, JSON.stringify(resultMicroConfigData)); // 写入 新的 microConfig.json 数据
            // 是否 存在 public 目录
            // if (fs.existsSync(paths.appMsPublic)) {
            //   fs.copySync(
            //     paths.appMsPublic,
            //     path.resolve(paths.appRootBuild, `packages/${appPackage.name}`),
            //     {
            //       dereference: true,
            //       filter: (file) => file !== paths.appHtml,
            //     }
            //   );
            // }
            const isPublicMs = IS_PUBLIC_MS || !!microPackageConfig.public; // 默认为 true
            if (isPublicMs) {
                fs.writeFileSync(path.resolve(paths.appRootBuild, `packages/${appPackage.name}/package.js`), `
        (function(e, n) {
          "object" === typeof exports && "object" === typeof module ? module.exports = n() : "function" === typeof define && define.amd ? define([], n) : "object" === typeof exports ? exports["cpaasJsonp_packages/${appPackage.name}-package"](n()) : e["cpaasJsonp_packages/${appPackage.name}-package"](n())
        })(window, function() {
          return ${JSON.stringify(microPackageConfig)};
        });
      `);
            }
            const microMapConfigPathJsonp = path.resolve(paths.appRootBuild, 'packages/microConfig.js');
            const publicPackagesConfigData = {};
            Object.keys(resultMicroConfigData).forEach(name => {
                const packageConfig = resultMicroConfigData[name];
                // if (packageConfig.public) {
                publicPackagesConfigData[name] = packageConfig;
                // }
            });
            fs.writeFileSync(microMapConfigPathJsonp, `
      (function(e, n) {
        "object" === typeof exports && "object" === typeof module ? module.exports = n() : "function" === typeof define && define.amd ? define([], n) : "object" === typeof exports ? exports["cpaasJsonp_packages"](n()) : e["cpaasJsonp_packages"](n())
      })(window, function() {
        return ${JSON.stringify(publicPackagesConfigData)};
      });
    `);
        });
    }
    try {
        // 执行前已经 清空了 dist 目录
        const previousFileSizes = yield measureFileSizesBeforeBuild(paths.appRootBuild);
        const { stats, warnings, config } = (yield build(previousFileSizes));
        if (!stats) {
            return;
        }
        if (warnings.length) {
            console.log(chalk.yellow('Compiled with warnings.\n'));
            console.log(warnings.join('\n\n'));
            console.log('\nSearch for the ' +
                chalk.underline(chalk.yellow('keywords')) +
                ' to learn more about each warning.');
            console.log('To ignore, add ' +
                chalk.cyan('// eslint-disable-next-line') +
                ' to the line before.\n');
        }
        else {
            console.log(chalk.green('Compiled successfully.\n'));
        }
        console.log('File sizes after gzip:\n');
        // console.log(
        //   stats,
        //   previousFileSizes,
        //   paths.appRootBuild,
        // );
        // process.exit();
        printFileSizesAfterBuild(stats, previousFileSizes, paths.appRootBuild, WARN_AFTER_BUNDLE_GZIP_SIZE, WARN_AFTER_CHUNK_GZIP_SIZE);
        console.log();
        const publicUrl = paths.publicUrl;
        const publicPath = config.output.publicPath;
        const buildFolder = path.relative(process.cwd(), paths.appRootBuild);
        printHostingInstructions(appPackage, publicUrl, publicPath, buildFolder, useYarn);
    }
    catch (errMsg) {
        console.log(chalk.red('Failed to compile.\n'));
        // printBuildError(errMsg);
        console.error(errMsg);
        process.exit(1);
    }
    console.log(`模块 ${appPackage.name} 编译完毕`);
});
exports.default = bootstrap;
